﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Media;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.Helpers;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace MIBHunter
{
    public partial class Classname
    {
        #region Attackable

        private bool Attackable(WoWUnit target)
        {
            if (target != null && SpecialUnit.Contains(target.Entry))
            {
                return true;
            }

            if (!ValidUnit(target))
            {
                return false;
            }

            if (!IsEnemy(target))
            {
                return false;
            }

            if (Invulnerable(target))
            {
                return false;
            }

            if (DebuffCCBreakonDamage(target))
            {
                return false;
            }


            return true;
        }

        private bool Attackable(WoWUnit target, int range)
        {
            if (target == null)
            {
                return false;
            }

            if (SpecialUnit.Contains(target.Entry))
            {
                return true;
            }

            if (!ValidUnit(target))
            {
                return false;
            }

            if (DebuffCCBreakonDamage(target))
            {
                return false;
            }

            if (range > 5 && !target.InLineOfSpellSight)
            {
                return false;
            }

            if (range <= 5 && !target.IsWithinMeleeRange)
            {
                return false;
            }

            if (range > 5 && target.Distance2D - target.BoundingRadius > range)
            {
                return false;
            }

            if (!IsEnemy(target))
            {
                return false;
            }

            if (Invulnerable(target))
            {
                return false;
            }

            return true;
        }

        private bool AttackableValid(WoWUnit target)
        {
            if (target.Distance < 40 && !Invulnerable(target) &&
                !DebuffCCBreakonDamage(target) && IsEnemy(target) &&
                target.InLineOfSpellSight)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region  BattleStandard

        public Composite UseBattleStandard()
        {
            return
                new Decorator(
                    ret =>
                    MIBSettings.Instance.HealthStone &&
                    Me.Combat &&
                    Me.HealthPercent < MIBSettings.Instance.HealthStoneHP &&
                    Me.CurrentTarget != null &&
                    Me.CurrentTarget.CurrentHealth > Me.HealthPercent &&
                    Me.CurrentMap.IsBattleground,
                    new Action(delegate
                        {
                            if (Me.IsAlliance)
                            {
                                WoWItem bs = Me.BagItems.FirstOrDefault(o => o.Entry == 18606);
                                //18606 Alliance Battle Standard

                                if (!Me.HasAura("Alliance Battle Standard") && bs != null &&
                                    bs.CooldownTimeLeft.TotalMilliseconds <= MyLatency)
                                {
                                    bs.Use();
                                    Logging.Write("Use Battle Standard at " + Me.HealthPercent + "%");
                                }
                            }

                            if (Me.IsHorde)
                            {
                                WoWItem bs = Me.BagItems.FirstOrDefault(o => o.Entry == 18607);
                                //18606 Horde Battle Standard

                                if (!Me.HasAura("Horde Battle Standard") && bs != null &&
                                    bs.CooldownTimeLeft.TotalMilliseconds <= MyLatency)
                                {
                                    bs.Use();
                                    Logging.Write("Use Battle Standard at " + Me.HealthPercent + "%");
                                }
                            }

                            return RunStatus.Failure;
                        })
                    );
        }

        #endregion

        #region CastSpell

        public static DateTime HoldRotationWhileFlying = DateTime.Now;
        public static WoWUnit LastCastUnit;
        public static WoWUnit LastCastUnitSoothingMist = Me;
        public static DateTime LastCastTime = DateTime.Now;
        public string LastCastSpell = "";
        private string _writeReason;

        public void CastSpell(string spellName, WoWUnit u, string reason = "")
        {
            SpellManager.Cast(spellName, u);

            LastCastTime = DateTime.Now;

            string barTwo;
            if (Me.HasAura("Stance of the Wise Serpent"))
            {
                barTwo = "Chi: " + Me.CurrentChi + " Mana: " + Math.Round(Me.ManaPercent);
            }
            else
            {
                barTwo = "Chi: " + Me.CurrentChi + " Energy: " + Math.Round(Me.EnergyPercent);
            }

            string unitLogName;
            if (u == Me)
            {
                unitLogName = "Myself";
            }
            else if (u.IsPlayer)
            {
                unitLogName = u.Class.ToString();
            }
            else if (u.IsPet)
            {
                unitLogName = u.CreatureType.ToString();
            }
            else
            {
                unitLogName = u.Name;
            }

            _writeReason = "";
            _writeReason = reason;

            Color colorlog;
            if (AttackSpells.Contains(spellName))
            {
                colorlog = Colors.Yellow;
            }

            else if (DefendSpells.Contains(spellName))
            {
                colorlog = Colors.Green;
            }
            else if (SpecialSpells.Contains(spellName))
            {
                colorlog = Colors.OrangeRed;
            }
            else
            {
                colorlog = Colors.GreenYellow;
            }

            Logging.Write(colorlog, DateTime.Now.ToString("ss:fff") + " - hp: " +
                                    Math.Round(Me.HealthPercent) + " - " + barTwo + " - " +
                                    unitLogName + " - " +
                                    Math.Round(u.Distance, 2) + "y - " +
                                    Math.Round(u.HealthPercent) + " hp - " + spellName + " (" + _writeReason + ")");

            LastCastSpell = spellName;
            LastCastUnit = u;

            TickMilisecond = DateTime.Now;
        }

        #endregion

        #region CanCleanse

        public bool CanCleanse(WoWAura aura)
        {
            if (aura.Spell.DispelType != WoWDispelType.None)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region CanUseEquippedItem

        private static bool CanUseEquippedItem(WoWItem item)
        {
            // Check for engineering tinkers!
            var itemSpell = Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
            if (string.IsNullOrEmpty(itemSpell))
                return false;


            return item.Usable && item.Cooldown <= 0;
        }

        #endregion

        #region ConstantFace

        public void ConstantFace(WoWUnit unit)
        {
            if (MIBSettings.Instance.AutoFace && !IsOverrideModeOn && !Me.IsSafelyFacing(unit))
            {
                unit.Face();
                WoWMovement.ConstantFace(unit.Guid);
            }
        }

        #endregion

        #region CountDebuff

        public static double CountDebuff(WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                int numberofDebuff =
                    u.Debuffs.Values.Count(
                        debuff =>
                        (debuff.Spell.DispelType == WoWDispelType.Magic ||
                         debuff.Spell.DispelType == WoWDispelType.Poison ||
                         debuff.Spell.DispelType == WoWDispelType.Disease));

                return numberofDebuff;
            }
        }

        public static double CountDebuffMagic(WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                int numberofDebuff =
                    u.Debuffs.Values.Count(
                        debuff => (debuff.Spell.DispelType == WoWDispelType.Magic));

                return numberofDebuff;
            }
        }

        public double CountDebuffRootandSnareMechanic(WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                return
                    u.ActiveAuras.Values.Count(
                        debuff =>
                        (debuff.Spell.Mechanic == WoWSpellMechanic.Snared ||
                         debuff.Spell.Mechanic == WoWSpellMechanic.Rooted));
            }
        }

        #endregion

        #region CountMeleeDPSTarget

        private int CountMeleeDPSTarget(WoWUnit target)
        {
            {
                if (Me.CurrentMap.IsArena || Me.CurrentMap.IsBattleground)
                {
                    return NearbyUnFriendlyPlayers.Count(
                        unit =>
                        unit.GotTarget &&
                        unit.CurrentTarget == target &&
                        TalentSort(unit) == 1 &&
                        unit.Location.Distance(target.Location) < 15 &&
                        !DebuffCC(unit));
                }
                return NearbyUnFriendlyUnits.Count(
                    unit =>
                    unit.GotTarget &&
                    unit.CurrentTarget == target &&
                    unit.Location.Distance(target.Location) < 15 &&
                    !DebuffCC(unit));
            }
        }

        #endregion

        #region CountEneyNeary

        private double CountEneyNeary(WoWObject unitCenter, float distance)
        {
            return
                NearbyUnFriendlyUnits.Where(
                    unit =>
                    unitCenter.Location.Distance(unit.Location) <= distance &&
                    unit.Combat && !unit.IsPet &&
                    (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember ||
                     unit.IsTargetingMeOrPet)).Aggregate
                    <WoWUnit, double>(0, (current, unit) => current + 1);
        }

        #endregion

        #region CountEneyNearyMeFacing

        private double CountEneyNearyMeFacing(int distance)
        {
            return
                FarFriendlyUnits.Where(
                    unit =>
                    Me.IsFacing(unit) &&
                    Attackable(unit, distance) &&
                    !unit.IsPet &&
                    (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember ||
                     unit.IsTargetingMeOrPet)).Aggregate
                    <WoWUnit, double>(0, (current, unit) => current + 1);
        }

        #endregion

        #region CountEneyNearyWorthDropStatue

        private double CountEneyNearyWorthDropStatue(int distance)
        {
            return
                NearbyUnFriendlyUnits.Where(
                    unit =>
                    Me.IsFacing(unit) &&
                    Attackable(unit, distance) &&
                    !unit.IsPet
                    ).Aggregate
                    <WoWUnit, double>(0, (current, unit) => current + 1);
        }

        #endregion

        #region CountFriendlyInLineNeedHeal

        private double CountFriendlyInLine(WoWObject unitTarget, float distance, double healthPercent)
        {
            return (from WoWPlayer player in NearbyFriendlyPlayers
                    let playermidpoint =
                        WoWMathHelper.CalculatePointFrom(Me.Location, unitTarget.Location,
                                                         (float) unitTarget.Distance - (float) player.Distance)
                    where
                        unitTarget.Distance < distance && player.Distance < unitTarget.Distance &&
                        player.Location.Distance(playermidpoint) <= 8 && player.HealthPercent <= healthPercent
                    select player).Count();
        }

        #endregion

        #region CountFriendlyNearyNeedHeal

        private double CountFriendlyNearNeedHeal(WoWObject unitCenter, float distance, double healthPercent)
        {
            return
                NearbyFriendlyPlayers.Where(
                    unit =>
                    unitCenter.Location.Distance(unit.Location) <= distance &&
                    unit.HealthPercent <= healthPercent).Aggregate
                    <WoWUnit, double>(0, (current, unit) => current + 1);
        }

        #endregion

        #region FacingOverride

        private bool FacingOverride(WoWUnit unit)
        {
            {
                if (unit == null)
                {
                    return false;
                }

                if (SpecialUnit.Contains(unit.Entry))
                {
                    return true;
                }

                if (!IsOverrideModeOn && MIBSettings.Instance.AutoFace)
                {
                    return true;
                }

                if (TreeRoot.Current.Name == "Questing" ||
                    TreeRoot.Current.Name == "Grind Bot" ||
                    TreeRoot.Current.Name == "BGBuddy" ||
                    TreeRoot.Current.Name == "DungeonBuddy" ||
                    TreeRoot.Current.Name == "Mixed Mode")
                {
                    return true;
                }

                if (Me.IsFacing(unit))
                {
                    return true;
                }

                return false;
            }
        }

        #endregion

        #region GCD

        private static DateTime _gcdReady;

        private void UpdateGCD()
        {
            _gcdReady = DateTime.Now + SpellManager.Spells[GCDCheckSpell].CooldownTimeLeft;
        }

        private bool GCDL()
        {
            if ((DateTime.Now - LastCastTime).TotalMilliseconds < MyLatency &&
                SpellManager.Spells[GCDCheckSpell].CooldownTimeLeft.TotalMilliseconds > MyLatency)
            {
                return true;
            }
            return false;
        }

        private bool Casting()
        {
            if (Me.IsChanneling && Me.ChanneledCastingSpellId == 115175) //Soothing Mist
            {
                return false;
            }

            if (Me.IsCasting)
            {
                return true;
            }

            if (Me.IsChanneling) //Cracking Jade Ligntning
            {
                return true;
            }

            return false;
        }


        public bool CastingorGCDL()
        {
            if (Casting() || GCDL())
            {
                return true;
            }
            return false;
        }

        #endregion

        #region GetCurrentSpec

        public static string CurrentSpec;

        public static string GetCurrentSpec()
        {
            switch (Me.Specialization)
            {
                case WoWSpec.HunterBeastMastery:
                    CurrentSpec = "BeastMastery";
                    break;
                case WoWSpec.HunterMarksmanship:
                    CurrentSpec = "Marksmanship";
                    break;
                case WoWSpec.HunterSurvival:
                    CurrentSpec = "Survival";
                    break;
            }
            return CurrentSpec;
        }

        #endregion

        #region GetAsyncKeyState

        [DllImport("user32.dll")]
        private static extern short GetAsyncKeyState(Keys vKey);

        #endregion

        #region GetSpellCooldown

        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                {
                    return results.Override.CooldownTimeLeft;
                }
                return results.Original.CooldownTimeLeft;
            }

            return TimeSpan.MaxValue;
        }

        #endregion

        #region GetAllMyAuras

        public DateTime LastGetAllMyAuras = DateTime.Now;

        public void DumpAuras()
        {
            if (LastGetAllMyAuras.AddSeconds(10) < DateTime.Now)
            {
                int i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (WoWAura aura in Me.GetAllAuras())
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.GetAllAuras Name: " + aura.Name + " - SpellId: " + aura.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.Auras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.Auras - Name: " + aura.Value.Name + " - SpellId: " + aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.ActiveAuras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.ActiveAuras - Name: " + aura.Value.Name + " - SpellId: " +
                                  aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.PassiveAuras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.PassiveAuras - Name: " + aura.Value.Name + " - SpellId: " +
                                  aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                LastGetAllMyAuras = DateTime.Now;
            }
        }

        #endregion

        #region GetDistance

        private static float GetDistance(WoWUnit target)
        {
            {
                if (target != null)
                {
                    return (float) Math.Max(0f, target.Distance2D - target.BoundingRadius);
                }
                return 0;
            }
        }

        #endregion

        #region GetPlayerGotMyHandofSacrifice

        public WoWUnit PlayerGotMyHandofSacrifice;

        #endregion

        #region GetUnitDispellerAround

        public WoWUnit UnitDispellerAround;

        private bool GetUnitDispellerAround()
        {
            UnitDispellerAround = null;
            UnitDispellerAround = (from unit in NearbyUnFriendlyUnits
                                   orderby unit.Distance ascending
                                   where unit.IsPlayer
                                   where
                                       unit.Class == WoWClass.Hunter || unit.Class == WoWClass.Mage ||
                                       unit.Class == WoWClass.Priest || unit.Class == WoWClass.Shaman
                                   where AttackableValid(unit)
                                   select unit).FirstOrDefault();

            return UnitDispellerAround != null;
        }

        #endregion

        #region GetUnitLowThreat

        private WoWUnit _unitLowThreat;

        private bool GetUnitLowThreat()
        {
            _unitLowThreat = null;
            _unitLowThreat = (from unit in NearbyUnFriendlyUnits
                              orderby unit.ThreatInfo.RawPercent ascending
                              where Me.Combat
                              where Me.CurrentMap.IsDungeon || Me.CurrentMap.IsRaid
                              where (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember ||
                                     unit.IsTargetingMeOrPet)
                              where unit.IsWithinMeleeRange
                              select unit).FirstOrDefault();
            return _unitLowThreat != null;
        }

        #endregion

        #region GetUnitNear

        public WoWUnit UnitNear;

        private bool GetUnitNear()
        {
            {
                UnitNear = null;
                UnitNear = (from unit in NearbyUnFriendlyUnits
                            orderby unit.Distance ascending
                            where Me.Combat
                            where Me.CurrentMap.IsDungeon || Me.CurrentMap.IsRaid
                            where (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember ||
                                   unit.IsTargetingMeOrPet)
                            select unit).FirstOrDefault();
                return UnitNear != null;
            }
        }

        #endregion

        #region Healable

        private bool Healable(WoWUnit u)
        {
            if (ValidUnit(u) && u.Distance < 40 && !IsEnemy(u) && !DebuffDoNotHeal(u) && u.InLineOfSpellSight)
            {
                return true;
            }
            return false;
        }

        //prevent double ValidUnit Check
        private bool HealableValid(WoWUnit u)
        {
            if (u.Distance < 40 && !IsEnemy(u) && !DebuffDoNotHeal(u) && u.InLineOfSpellSight)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region Hold

        public Composite Hold()
        {
            return
                new Decorator(
                    ret =>
                    Me.HasAura("Drink") && 
                    Me.FocusPercent < MIBSettings.Instance.DoNotHealAbove ||
                    Me.HasAura("Food") && Me.CurrentHealth < MIBSettings.Instance.DoNotHealAbove ||
                    Me.IsChanneling && !Me.IsAlive || InputLasting > DateTime.Now,
                    new Action(delegate
                        {
                            Logging.Write("Warte kurz");
                            return RunStatus.Success;
                        })
                    );
        }

        #endregion

        #region IndexToKeys

        public Keys KeyTwo;

        private Keys IndexToKeys(int index)
        {
            switch (index)
            {
                case 1:
                    return Keys.A;
                case 2:
                    return Keys.B;
                case 3:
                    return Keys.C;
                case 4:
                    return Keys.D;
                case 5:
                    return Keys.E;
                case 6:
                    return Keys.F;
                case 7:
                    return Keys.G;
                case 8:
                    return Keys.H;
                case 9:
                    return Keys.I;
                case 10:
                    return Keys.J;
                case 11:
                    return Keys.K;
                case 12:
                    return Keys.L;
                case 13:
                    return Keys.M;
                case 14:
                    return Keys.N;
                case 15:
                    return Keys.O;
                case 16:
                    return Keys.P;
                case 17:
                    return Keys.Q;
                case 18:
                    return Keys.R;
                case 19:
                    return Keys.S;
                case 20:
                    return Keys.T;
                case 21:
                    return Keys.U;
                case 22:
                    return Keys.V;
                case 23:
                    return Keys.W;
                case 24:
                    return Keys.X;
                case 25:
                    return Keys.Y;
                case 26:
                    return Keys.Z;
                case 27:
                    return Keys.NumPad1;
                case 28:
                    return Keys.NumPad2;
                case 29:
                    return Keys.NumPad3;
                case 30:
                    return Keys.NumPad4;
                case 31:
                    return Keys.NumPad5;
                case 32:
                    return Keys.NumPad6;
                case 33:
                    return Keys.NumPad7;
                case 34:
                    return Keys.NumPad8;
                case 35:
                    return Keys.NumPad9;
                case 36:
                    return Keys.NumPad0;
                case 37:
                    return Keys.Up;
                case 38:
                    return Keys.Down;
                case 39:
                    return Keys.Left;
                case 40:
                    return Keys.Right;
            }
            return Keys.None;
        }

        #endregion

        #region InputBlockCheck

        public DateTime InputLasting;

        [DllImport("user32.dll")]
        private static extern bool BlockInput(bool block);

        public void InputBlockCheck()
        {
            if (InputLasting > DateTime.Now)
            {
                SendKeys.Flush();
                BlockInput(true);
            }

            if (InputLasting <= DateTime.Now)
            {
                SendKeys.Flush();
                BlockInput(false);
            }
        }

        public void InputBlockUse(bool switcher, string spellName)
        {
            if (MIBSettings.Instance.InputBlockMode &&
                switcher && !IsOverrideModeOn && spellName == "Fists of Fury" && MIBSettings.Instance.BlockInputFoF)
            {
                InputLasting = DateTime.Now + TimeSpan.FromMilliseconds(MIBSettings.Instance.BlockInputDelay);
                BlockInput(true);
            }
        }

        #endregion

        #region IsHealing

        private static bool IsHealing()
        {
            return Me.IsCasting &&
                   (Me.CastingSpell.Name == "Flash of Light" || Me.CastingSpell.Name == "Divine Light" ||
                    Me.CastingSpell.Name == "Holy Light" || Me.CastingSpell.Name == "Holy Radiance");
        }

        #endregion

        #region IsGroupHealingOn

        private bool _groupHealingOn;

        public bool IsGroupHealingOn()
        {
            if (!SpellManager.HasSpell("Holy Insight"))
            {
                _groupHealingOn = false;
                return false;
            }

            if (MIBSettings.Instance.Group1 &&
                MIBSettings.Instance.Group2 &&
                MIBSettings.Instance.Group3 &&
                MIBSettings.Instance.Group4 &&
                MIBSettings.Instance.Group5 &&
                MIBSettings.Instance.Group6 &&
                MIBSettings.Instance.Group7 &&
                MIBSettings.Instance.Group8
                )
            {
                _groupHealingOn = false;
                return false;
            }

            if (!MIBSettings.Instance.Group1 &&
                !MIBSettings.Instance.Group2 &&
                !MIBSettings.Instance.Group3 &&
                !MIBSettings.Instance.Group4 &&
                !MIBSettings.Instance.Group5 &&
                !MIBSettings.Instance.Group6 &&
                !MIBSettings.Instance.Group7 &&
                !MIBSettings.Instance.Group8
                )
            {
                _groupHealingOn = false;
                return false;
            }

            if (!Me.IsInMyRaid)
            {
                _groupHealingOn = false;
                return false;
            }

            if (Me.CurrentMap.IsBattleground)
            {
                _groupHealingOn = false;
                return false;
            }

            Logging.Write("----------------------------------");
            Logging.Write("Selective Gruppenheilung Modus An");
            Logging.Write("----------------------------------");
            _groupHealingOn = true;
            return true;
        }

        #endregion

        #region IsEnemy

        public WoWUnit MyPartyorRaidUnit;

        public bool IsMyPartyRaidMember(WoWUnit u)
        {
            if (u == null || !u.IsValid)
            {
                return false;
            }

            if (_groupHealingOn && !GroupHealingMembers.Contains(u))
            {
                return false;
            }

            if (!u.IsPlayer)
            {
                if (Me.PartyMembers.Contains(u.CreatedByUnit) || Me.RaidMembers.Contains(u.CreatedByUnit))
                {
                    return true;
                }
            }
            else
            {
                if (Me.PartyMembers.Contains(u) || Me.RaidMembers.Contains(u))
                {
                    return true;
                }
            }

            return false;
        }

        public bool IsEnemy(WoWUnit target)
        {
            if (target == null)
            {
                return false;
            }

            if (target.Entry == 62442 && !target.Attackable) //tsulong
            {
                return false;
            }

            if (target.HasAura("Reshape Life") || //Reshape Life
                target.HasAura("Convert")) //Convert
            {
                return true;
            }

            if (IsMyPartyRaidMember(target))
            {
                return false;
            }

            if (Me.CurrentMap.IsArena || Me.CurrentMap.IsBattleground)
            {
                return true;
            }

            if (!target.IsFriendly || target.Name.Contains("Dummy") && Me.Combat && Me.IsFacing(target))
            {
                return true;
            }
            return false;
        }

        #endregion

        #region IsMeorFocus

        public bool IsMeorFocus(WoWUnit target)
        {
            if (target == Me ||
                target == Me.FocusedUnit && ValidUnit(Me.FocusedUnit) && !IsEnemy(Me.FocusedUnit) ||
                target == Me.CurrentTarget && ValidUnit(Me.CurrentTarget) && !IsEnemy(Me.CurrentTarget) ||
                Me.CurrentMap.IsArena)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region MeIsTank

        public static bool MeIsTank
        {
            get
            {
                return (StyxWoW.Me.Role & WoWPartyMember.GroupRole.Tank) != 0;
            }
        }

        #endregion

        #region MyAura

        public bool MyAura(string auraName, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return false;

                bool aura = u.GetAllAuras().Any(a => a.Name == auraName && a.CreatorGuid == Me.Guid);

                return aura;
            }
        }


        public bool MyAura(int auraID, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return false;

                bool aura = u.GetAllAuras().Any(a => a.SpellId == auraID && a.CreatorGuid == Me.Guid);

                return aura;
            }
        }

        #endregion

        #region MyAuraTimeLeft

        public double MyAuraTimeLeft(string auraName, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        public double MyAuraTimeLeft(int auraID, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        #endregion

        #region UnitAuraTimeLeft

        public double UnitAuraTimeLeft(string auraName, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        public double UnitAuraTimeLeft(int auraID, WoWUnit u)
        {
            {
                if (u == null)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        #endregion

        #region MyAuraStackCount

        public double MyAuraStackCount(string auraName, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
        }

        public double MyAuraStackCount(int auraID, WoWUnit u)
        {
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
        }

        #endregion

        #region SafelyFacingTarget

        public void SafelyFacingTarget(WoWUnit unit)
        {
            {
                if (MIBSettings.Instance.AutoFace && !IsOverrideModeOn && unit != null)
                {
                    unit.Face();
                }
            }
        }

        #endregion

        #region SetAutoAttack

        public Composite SetAutoAttack()
        {
            return new Action(delegate
                {
                    if (Me.Combat && Me.IsAutoAttacking && Me.CurrentTarget != null &&
                        Me.CurrentTarget.IsValid &&
                        (Me.CurrentTarget.HasAura("Water Shield") && Me.CurrentTarget.IsPlayer &&
                         Me.IsFFAPvPFlagged ||
                         DebuffCCBreakonDamage(Me.CurrentTarget) || Invulnerable(Me.CurrentTarget) ||
                         !MIBSettings.Instance.AutoAttack))
                    {
                        Lua.DoString("RunMacroText('/stopattack');");
                    }

                    return RunStatus.Failure;
                });
        }

        #endregion

        #region SpellType

        private static readonly HashSet<string> AttackSpells = new HashSet<string>
            {
                "Blackout Kick",
                "Breath of Fire",
                "Crackling Jade Lightning",
                "Dizzying Haze",
                "Energizing Brew",
                "Flying Serpent Kick",
                "Invoke Xuen, the White Tiger",
                "Jab",
                "Keg Smash",
                "Leer of the Ox",
                "Path of Blossoms",
                "Provoke",
                "Rising Sun Kick",
                "Roll",
                "Spinning Crane Kick",
                "Spinning Fire Blossom",
                "Tiger Palm",
                "Tigereye Brew",
                "Touch of Death",
            };

        private static readonly HashSet<string> DefendSpells = new HashSet<string>
            {
                "Avert Harm",
                "Dampen Harm",
                "Diffuse Magic",
                "Elusive Brew",
                "Enveloping Mist",
                "Fortifying Brew",
                "Guard",
                "Healing Sphere",
                "Mana Tea",
                "Purifying Brew",
                "Renewing Mist",
                "Resuscitate",
                "Soothing Mist",
                "Summon Black Ox Statue",
                "Summon Jade Serpent Statue",
                "Surging Mist",
                "Transcendence",
                "Transcendence: Transfer",
                "Uplift",
                "Zen Meditation",
                "Zen Sphere",
            };

        private static readonly HashSet<string> SpecialSpells = new HashSet<string>
            {
                "Charging Ox Wave",
                "Clash",
                "Detox",
                "Disable",
                "Fists of Fury",
                "Grapple Weapon",
                "Leg Sweep",
                "Paralysis",
                "Spear Hand Strike",
            };

        #endregion

        #region TalentSort

        public byte TalentSort(WoWUnit target)
        {
            if (target == null)
            {
                return 0;
            }

            if (!target.IsPlayer)
            {
                return 0;
            }

            if (target.Class == WoWClass.DeathKnight)
            {
                return 1;
            }

            if (target.Class == WoWClass.Druid)
            {
                if (target.Buffs.ContainsKey("Moonkin Form"))
                    return 3;
                if ((target.Buffs.ContainsKey("Leader of the Pack") &&
                     target.Buffs["Leader of the Pack"].CreatorGuid == target.Guid) ||
                    target.MaxMana < target.MaxHealth/2)
                    return 1;
                return 4;
            }

            if (target.Class == WoWClass.Hunter)
            {
                return 2;
            }

            if (target.Class == WoWClass.Mage)
            {
                return 3;
            }

            if (target.Class == WoWClass.Monk)
            {
                if (target.MaxMana >= target.MaxHealth/2)
                    return 4;
                return 1;
            }

            if (target.Class == WoWClass.Paladin)
            {
                if (target.MaxMana > target.MaxMana/2)
                    return 4;
                return 1;
            }

            if (target.Class == WoWClass.Priest)
            {
                if (target.HasAura("Shadowform"))
                    return 3;
                return 4;
            }

            if (target.Class == WoWClass.Rogue)
            {
                return 1;
            }

            if (target.Class == WoWClass.Shaman)
            {
                if (target.MaxMana < target.MaxHealth/2)
                    return 1;
                if (target.Buffs.ContainsKey("Elemental Oath") &&
                    target.Buffs["Elemental Oath"].CreatorGuid == target.Guid)
                    return 3;
                return 4;
            }

            if (target.Class == WoWClass.Warlock)
            {
                return 3;
            }

            if (target.Class == WoWClass.Warrior)
            {
                return 1;
            }

            return 0;
        }

        public byte TalentSortSimple(WoWUnit target)
        {
            byte sortSimple = TalentSort(target);

            if (sortSimple == 4)
            {
                return 4;
            }

            if (sortSimple < 4 && sortSimple > 0)
            {
                return 1;
            }

            return 0;
        }

        #endregion

        #region UpdateStatusEvent

        public void UpdateStatusEvent(object sender, LuaEventArgs args)
        {
            MIBSettings.Instance.UpdateStatus = true;
        }

        #endregion

        #region OnBotStartedEvent

        private bool RollRemoveSnare;

        private void OnBotStartedEvent(object o)
        {
            if (Me.Inventory.Equipped.Hands != null &&
                Me.Inventory.Equipped.Hands.Name.Contains("Gladiator's Ironskin Gloves"))
            {
                RollRemoveSnare = true;
            }
            Logging.Write("----------------------------------");
            Logging.Write("Update Status bei Bot Start");
            Logging.Write("----------------------------------");
            MIBSettings.Instance.Pause = false;
            MIBSettings.Instance.UpdateStatus = true;
        }

        #endregion

        #region SpecialUnit

        private static readonly HashSet<uint> SpecialUnit = new HashSet<uint>
            {
                60410, //Elegon
                60776, //Empyreal Focus
                60793, //Celestial Protector
                60913, //Energy Charge
                60143, //garajal-the-spiritbinder
                60412, //Empyreal Focus
            };

        #endregion

        #region UpdateGroupHealingMembers

        public void UpdateGroupChangeEvent(object sender, LuaEventArgs args)
        {
            if (IsGroupHealingOn())
            {
                Logging.Write("Update Selective Group Healing on Group Member Change");
                MIBSettings.Instance.UpdateStatus = true;
            }
        }

        public List<WoWPlayer> GroupHealingMembers = new List<WoWPlayer>();

        public void UpdateGroupHealingMembers()
        {
            GroupHealingMembers.Clear();

            if (IsGroupHealingOn())
            {
                foreach (var woWPartyMember in GroupMembers)
                {
                    if (woWPartyMember.ToPlayer() != null)
                    {
                        if (MIBSettings.Instance.Group1 && woWPartyMember.GroupNumber == 0 ||
                            MIBSettings.Instance.Group2 && woWPartyMember.GroupNumber == 1 ||
                            MIBSettings.Instance.Group3 && woWPartyMember.GroupNumber == 2 ||
                            MIBSettings.Instance.Group4 && woWPartyMember.GroupNumber == 3 ||
                            MIBSettings.Instance.Group5 && woWPartyMember.GroupNumber == 4 ||
                            MIBSettings.Instance.Group6 && woWPartyMember.GroupNumber == 5 ||
                            MIBSettings.Instance.Group7 && woWPartyMember.GroupNumber == 6 ||
                            MIBSettings.Instance.Group8 && woWPartyMember.GroupNumber == 7)
                        {
                            Logging.Write("Add " + woWPartyMember.ToPlayer().Class + " in Group: " +
                                          (Convert.ToByte(woWPartyMember.GroupNumber) + 1) +
                                          " to Selective Group Healing");
                            GroupHealingMembers.Add(woWPartyMember.ToPlayer());
                        }
                    }
                }

                if (GroupHealingMembers.Any())
                {
                    Logging.Write("----------------------------------");
                    Logging.Write("You are assigned to Heal " + GroupHealingMembers.Count() + " Members");
                    Logging.Write("You will also heal your Target, your Focus and Yourself!");
                    Logging.Write("----------------------------------");
                }
            }
        }

        #endregion

        #region UpdateMyLatency

        public static readonly double MyLatency = 300;

        public static void UpdateMyLatency()
        {
        }

        #endregion

        #region UpdateMyTalent

        private static string _hasTalent = "";

        private void UpdateMyTalentEvent(object sender, LuaEventArgs args)
        {
            UpdateMyTalent();
        }

        public int ParalysisBonusRange;

        public void UpdateMyTalent()
        {
            _hasTalent = "";
            for (int i = 1; i <= 18; i++)
            {
                _hasTalent = _hasTalent +
                             Lua.GetReturnVal<String>(
                                 string.Format(
                                     "local t= select(5,GetTalentInfo({0})) if t == true then return '['..select(1,GetTalentInfo({0}))..'] ' end return nil",
                                     i), 0);
            }

            ParalysisBonusRange = 0;
            if (SpellManager.HasSpell("Deadly Reach"))
            {
                ParalysisBonusRange = 15;
            }

            Logging.Write("----------------------------------");
            Logging.Write("Talent:");
            Logging.Write(_hasTalent);
            Logging.Write("----------------------------------");
            _hasTalent = "";
        }

        #endregion

        #region UseHealthstone

        private Composite UseHealthstone()
        {
            return
                new Decorator(
                    ret =>
                    MIBSettings.Instance.HealthStone &&
                    MIBSettings.Instance.HealthStoneHP != 0 &&
                    Me.Combat &&
                    Me.HealthPercent < MIBSettings.Instance.HealthStoneHP &&
                    Me.CurrentTarget != null &&
                    Me.CurrentTarget.CurrentHealth > Me.HealthPercent,
                    new Action(delegate
                        {
                            WoWItem hs = Me.BagItems.FirstOrDefault(o => o.Entry == 5512); //5512 Healthstone
                            if (hs != null && hs.CooldownTimeLeft.TotalMilliseconds <= MyLatency)
                            {
                                hs.Use();
                                Logging.Write("Benutze Gesundheitstein bei " + Me.HealthPercent + "%");
                            }
                            return RunStatus.Failure;
                        })
                    );
        }

        #endregion

        #region UpdateMyNoGCDSpell

        private static readonly HashSet<string> NoGCDSpells = new HashSet<string>();

        public void UpdateMyNoGCDSpell()
        {
            if (SpellManager.HasSpell("Arcane Torrent"))
            {
                NoGCDSpells.Add("Arcane Torrent");
            }

            if (SpellManager.HasSpell("Ardent Defender"))
            {
                NoGCDSpells.Add("Ardent Defender");
            }

            if (SpellManager.HasSpell("Avenging Wrath"))
            {
                NoGCDSpells.Add("Avenging Wrath");
            }

            if (HasGlyph.Contains("63218"))
            {
                NoGCDSpells.Add("Beacon of Light");
            }

            if (SpellManager.HasSpell("Devotion Aura"))
            {
                NoGCDSpells.Add("Devotion Aura");
            }

            if (SpellManager.HasSpell("Divine Favor"))
            {
                NoGCDSpells.Add("Divine Favor");
            }

            if (SpellManager.HasSpell("Divine Protection"))
            {
                NoGCDSpells.Add("Divine Protection");
            }

            if (SpellManager.HasSpell("Guardian of Ancient Kings"))
            {
                NoGCDSpells.Add("Guardian of Ancient Kings");
            }

            if (SpellManager.HasSpell("Holy Avenger"))
            {
                NoGCDSpells.Add("Holy Avenger");
            }

            if (SpellManager.HasSpell("Lay on Hands"))
            {
                NoGCDSpells.Add("Lay on Hands");
            }

            if (SpellManager.HasSpell("Rebuke"))
            {
                NoGCDSpells.Add("Rebuke");
            }

            if (SpellManager.HasSpell("Reckoning"))
            {
                NoGCDSpells.Add("Reckoning");
            }


            Logging.Write("----------------------------------");
            Logging.Write("Casts ohne globalen Cooldown:");
            foreach (string spell in NoGCDSpells)
            {
                Logging.Write(" -" + spell);
            }
            Logging.Write("----------------------------------");
        }

        #endregion

        #region UpdateMyGlyph

        public void UpdateMyGlyphEvent(object sender, LuaEventArgs args)
        {
            UpdateMyGlyph();
        }

        public string HasGlyph;
        public string HasGlyphName;
        public int TouchofKarmaBonusRange;
        public int ExpelHarmBonusRange;
        public int TranscendenceRangeBonus;

        public void UpdateMyGlyph()
        {
            HasGlyph = "";
            HasGlyphName = "";

            var glyphCount = Lua.GetReturnVal<int>("return GetNumGlyphSockets()", 0);

            if (glyphCount != 0)
            {
                for (int i = 1; i <= glyphCount; i++)
                {
                    string lua =
                        String.Format(
                            "local enabled, glyphType, glyphTooltipIndex, glyphSpellID, icon = GetGlyphSocketInfo({0});if (enabled) then return glyphSpellID else return 0 end",
                            i);

                    var glyphSpellId = Lua.GetReturnVal<int>(lua, 0);

                    try
                    {
                        if (glyphSpellId > 0)
                        {
                            HasGlyphName = HasGlyphName + "[" + (WoWSpell.FromId(glyphSpellId)) + " - " + glyphSpellId +
                                           "] ";
                            HasGlyph = HasGlyph + "[" + glyphSpellId + "] ";
                        }
                        else
                        {
                            Logging.Write("Warnung: Keine Glyphe in slot " + i);
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Write("Ich konnte keine Glyphen ermitteln");
                        Logging.Write("Fehler: " + ex);
                    }
                }
            }
            TouchofKarmaBonusRange = 0;
            if (HasGlyph.Contains("[" + 125678 + "]"))
            {
                TouchofKarmaBonusRange = 15;
            }

            ExpelHarmBonusRange = 0;
            if (HasGlyph.Contains("[" + 119724 + "]"))
            {
                ExpelHarmBonusRange = 10;
            }

            TranscendenceRangeBonus = 0;
            if (HasGlyph.Contains("[" + 123023 + "]"))
            {
                ExpelHarmBonusRange = 10;
            }
            Logging.Write("----------------------------------");
            Logging.Write("Glyph:");
            Logging.Write(HasGlyphName);
            Logging.Write("----------------------------------");
        }

        #endregion

        #region UpdateStatus

        public void UpdateStatus()
        {
            if (MIBSettings.Instance.UpdateStatus)
                if (Me.IsValid)
                {
                    {
                        GetCurrentSpec();

                        //Reset BurstLast on start
                        BurstLast = DateTime.Now;

                        Logging.Write("----------------------------------");
                        Logging.Write("Baue Rotation auf Basis der Talente und Glyphen neu auf......");
                        Logging.Write("----------------------------------");
                        Logging.Write("");

                        if (TreeRoot.Current.Name == "LazyRaider" && !MIBSettings.Instance.AutoMove)
                        {
                            MIBSettings.Instance.AutoMove = false;
                        }

                        UpdateMyTalent();

                        UpdateMyGlyph();

                        UpdateMyNoGCDSpell();

                        UpdateMyLatency();

                        UpdateGroupHealingMembers();

                        _gcdReady = DateTime.Now;
                        Logging.Write("----------------------------------");
                        Logging.Write("Rotation neu aufbauen beendet");
                        Logging.Write("----------------------------------");
                        Logging.Write("");

                        Logging.Write("----------------------------------");
                        Logging.Write("Drück STRG + " + IndexToKeys(MIBSettings.Instance.PauseKey) +
                                      " zum Pause Modus umschalten");
                        Logging.Write("----------------------------------");
                        Logging.Write("");

                        Logging.Write("----------------------------------");
                        Logging.Write("Drück STRG + " + IndexToKeys(MIBSettings.Instance.AoEKey) +
                                      " zum AoE Modue umschalten");
                        Logging.Write("----------------------------------");
                        Logging.Write("");

                        if (MIBSettings.Instance.BurstKey > 6)
                        {
                            Logging.Write("----------------------------------");
                            Logging.Write("Drück STRG + " + IndexToKeys(MIBSettings.Instance.BurstKey - 6) +
                                          " zum Burst Modus umschalten");
                            Logging.Write("----------------------------------");
                            Logging.Write("");
                        }

                        CheckStanceState = true;

                        MIBSettings.Instance.UpdateStatus = false;
                    }
                }
        }

        #endregion

        #region ValidUnit

        public bool ValidUnit(WoWUnit u)
        {
            if (u == null || !u.IsValid || !u.Attackable || !u.IsAlive || u.IsDead || !u.CanSelect ||
                u.IsCritter && (u.CurrentTarget == null || u.CurrentTarget != null && u.CurrentTarget != Me) ||
                u.IsNonCombatPet || Blacklist.Contains(u.Guid, BlacklistFlags.All))
            {
                return false;
            }
            return true;
        }

        #endregion
    }
}